﻿' ----------------------------------------------------------------------------------
' Microsoft Developer & Platform Evangelism
' 
' Copyright (c) Microsoft Corporation. All rights reserved.
' 
' THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
' EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES 
' OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
' ----------------------------------------------------------------------------------
' The example companies, organizations, products, domain names,
' e-mail addresses, logos, people, places, and events depicted
' herein are fictitious.  No association with any real company,
' organization, product, domain name, email address, logo, person,
' places, or events is intended or should be inferred.
' ----------------------------------------------------------------------------------

Imports System.Text
Imports System.Runtime.Serialization
Imports System.Net.Browser
Imports System.IO
Imports Microsoft.Samples.WindowsPhoneCloud.StorageClient.Exceptions

Namespace Credentials

    Public Class AuthenticationClient
        Implements IAuthenticationClient
        Private Const LoginSignatureOperation As String = "/login"
        Private Const ValidateSignatureOperation As String = "/validate"
        Private Const RegisterSignatureOperation As String = "/register"

        Private serviceUri As String
        Private clientHttpValue As IWebRequestCreate

        Public Sub New(ByVal serviceUri As String)
            Me.serviceUri = serviceUri
        End Sub

        Friend Property ClientHttp() As IWebRequestCreate
            Get
                Return If(Me.clientHttpValue IsNot Nothing, Me.clientHttpValue, WebRequestCreator.ClientHttp)
            End Get

            Set(ByVal value As IWebRequestCreate)
                Me.clientHttpValue = value
            End Set
        End Property

        Public Sub Login(ByVal userName As String, ByVal password As String, ByVal successCallback As Action(Of AuthenticationSuccessArgs), ByVal exceptionCallback As Action(Of AuthenticationExceptionArgs)) Implements IAuthenticationClient.Login
            If String.IsNullOrEmpty(userName) OrElse String.IsNullOrEmpty(password) Then
                Return
            End If

            Dim uriBuilder = New UriBuilder(Me.serviceUri)
            uriBuilder.Path &= LoginSignatureOperation

            Dim request = Me.ClientHttp.Create(uriBuilder.Uri)
            request.Method = "POST"
            request.ContentType = "text/xml"

            Dim data = New Login With {.UserName = userName, .Password = password}
            Dim postData = String.Empty

            Using stream = New MemoryStream()
                Dim serializer = New DataContractSerializer(GetType(Login))
                serializer.WriteObject(stream, data)
                Dim contextAsByteArray() As Byte = stream.ToArray()
                postData = Encoding.UTF8.GetString(contextAsByteArray, 0, contextAsByteArray.Length)
            End Using

            request.BeginGetRequestStream(
                Sub(ar)
                    Dim postStream = request.EndGetRequestStream(ar)
                    Dim byteArray = Encoding.UTF8.GetBytes(postData)
                    postStream.Write(byteArray, 0, postData.Length)
                    postStream.Close()
                    request.BeginGetResponse(
                        Sub(asyncResult)
                            Dim token = String.Empty
                            Try
                                Dim response = request.EndGetResponse(asyncResult)
                                Dim serializer = New DataContractSerializer(GetType(String))
                                token = TryCast(serializer.ReadObject(response.GetResponseStream()), String)
                                If String.IsNullOrEmpty(token) Then
                                    ' Wrong credentials.
                                    exceptionCallback(New AuthenticationExceptionArgs With {.WrongCredentials = True, .IsError = False})
                                Else
                                    ' Success.
                                    successCallback(New AuthenticationSuccessArgs With {.UserName = userName, .AuthenticationToken = token})
                                End If
                            Catch exception As Exception
                                ' Error.
                                Dim webException = TryCast(exception, WebException)
                                If webException IsNot Nothing Then
                                    exceptionCallback(New AuthenticationExceptionArgs With {.Exception = StorageClientExceptionParser.ParseHttpWebException(webException), .WrongCredentials = False, .IsError = True})
                                Else
                                    exceptionCallback(New AuthenticationExceptionArgs With {.Exception = New HttpWebException(exception.GetBaseException().Message), .WrongCredentials = False, .IsError = True})
                                End If
                            End Try
                        End Sub, Nothing)
                End Sub,
                request)
        End Sub

        Public Sub Validate(ByVal token As String, ByVal successCallback As Action(Of AuthenticationSuccessArgs), ByVal exceptionCallback As Action(Of AuthenticationExceptionArgs)) Implements IAuthenticationClient.Validate
            Dim uriBuilder = New UriBuilder(Me.serviceUri)
            uriBuilder.Path &= ValidateSignatureOperation

            Dim request = Me.ClientHttp.Create(uriBuilder.Uri)
            request.Method = "POST"
            request.ContentType = "text/xml"

            Dim postData = String.Empty

            Using stream = New MemoryStream()
                Dim serializer = New DataContractSerializer(GetType(String))
                serializer.WriteObject(stream, token)

                Dim contextAsByteArray = stream.ToArray()
                postData = Encoding.UTF8.GetString(contextAsByteArray, 0, contextAsByteArray.Length)
            End Using

            request.BeginGetRequestStream(
                Sub(ar)
                    Dim postStream = request.EndGetRequestStream(ar)
                    Dim byteArray = Encoding.UTF8.GetBytes(postData)
                    postStream.Write(byteArray, 0, postData.Length)
                    postStream.Close()
                    request.BeginGetResponse(
                        Sub(asyncResult)
                            Try
                                Dim response = request.EndGetResponse(asyncResult)
                                Dim reader = New StreamReader(response.GetResponseStream())
                                Dim serializer = New DataContractSerializer(GetType(String))
                                Dim userName = TryCast(serializer.ReadObject(response.GetResponseStream()), String)
                                reader.Close()
                                If String.IsNullOrEmpty(userName) Then
                                    ' Wrong credentials.
                                    exceptionCallback(New AuthenticationExceptionArgs With {.IsError = False, .WrongCredentials = True})
                                Else
                                    ' Success.
                                    successCallback(New AuthenticationSuccessArgs With {.UserName = userName, .AuthenticationToken = token})
                                End If
                            Catch exception As Exception
                                ' Error.
                                Dim webException = TryCast(exception, WebException)
                                If webException IsNot Nothing Then
                                    exceptionCallback(New AuthenticationExceptionArgs With {.Exception = StorageClientExceptionParser.ParseHttpWebException(webException), .IsError = True, .WrongCredentials = False})
                                Else
                                    exceptionCallback(New AuthenticationExceptionArgs With {.Exception = New HttpWebException(exception.GetBaseException().Message), .IsError = True, .WrongCredentials = False})
                                End If
                            End Try
                        End Sub, Nothing)
                End Sub,
                request)
        End Sub

        Public Sub Register(ByVal userName As String, ByVal email As String, ByVal password As String, ByVal confirmPassword As String, ByVal successCallback As Action(Of RegistrationSuccessArgs), ByVal exceptionCallback As Action(Of RegistrationExceptionArgs)) Implements IAuthenticationClient.Register
            If String.IsNullOrEmpty(userName) OrElse String.IsNullOrEmpty(email) OrElse String.IsNullOrEmpty(password) OrElse String.IsNullOrEmpty(confirmPassword) Then
                Return
            End If

            If Not password.Equals(confirmPassword, StringComparison.InvariantCulture) Then
                exceptionCallback(New RegistrationExceptionArgs With {.IsError = False, .Exception = New HttpWebException("The password does not match with its confirmation.")})
                Return
            End If

            Dim uriBuilder = New UriBuilder(Me.serviceUri)
            uriBuilder.Path &= RegisterSignatureOperation

            Dim request = Me.ClientHttp.Create(uriBuilder.Uri)
            request.Method = "POST"
            request.ContentType = "text/xml"

            Dim data = New RegistrationUser With {.Name = userName, .EMail = email, .Password = password}
            Dim postData = String.Empty

            Using stream = New MemoryStream()
                Dim serializer = New DataContractSerializer(GetType(RegistrationUser))
                serializer.WriteObject(stream, data)
                Dim contextAsByteArray() As Byte = stream.ToArray()
                postData = Encoding.UTF8.GetString(contextAsByteArray, 0, contextAsByteArray.Length)
            End Using

            request.BeginGetRequestStream(
                Sub(ar)
                    Dim postStream = request.EndGetRequestStream(ar)
                    Dim byteArray = Encoding.UTF8.GetBytes(postData)
                    postStream.Write(byteArray, 0, postData.Length)
                    postStream.Close()
                    request.BeginGetResponse(
                        Sub(asyncResult)
                            Dim status = String.Empty
                            Try
                                Dim response = request.EndGetResponse(asyncResult)
                                Dim serializer = New DataContractSerializer(GetType(String))
                                status = TryCast(serializer.ReadObject(response.GetResponseStream()), String)
                                If String.IsNullOrEmpty(status) OrElse (Not status.Equals("Success", StringComparison.OrdinalIgnoreCase)) Then
                                    ' Registration Failed.
                                    exceptionCallback(New RegistrationExceptionArgs With {.Exception = New HttpWebException(status), .IsError = False})
                                Else
                                    ' Success.
                                    successCallback(New RegistrationSuccessArgs With {.UserName = userName})
                                End If
                            Catch exception As Exception
                                ' Error.
                                Dim webException = TryCast(exception, WebException)
                                If webException IsNot Nothing Then
                                    exceptionCallback(New RegistrationExceptionArgs With {.Exception = StorageClientExceptionParser.ParseHttpWebException(webException), .IsError = True})
                                Else
                                    exceptionCallback(New RegistrationExceptionArgs With {.Exception = New HttpWebException(exception.GetBaseException().Message), .IsError = True})
                                End If
                            End Try
                        End Sub, Nothing)
                End Sub,
                request)
        End Sub
    End Class
End Namespace